﻿using System;

namespace ECommerce.Web.Models
{
    public abstract class Entity : EntityWithTypedId<int> { }

    public abstract class EntityWithTypedId<TId> : IEquatable<EntityWithTypedId<TId>>
    {
        private const int HashMultiplier = 397;

        private int? cachedHashCode;

        public virtual TId Id { get; set; }

        public virtual bool IsTransient()
        {
            return Id.Equals(default(TId));
        }

        public virtual bool Equals(EntityWithTypedId<TId> other)
        {
            if (other == null) { return false; }

            if (IsTransient() && other.IsTransient())
            {
                return Object.ReferenceEquals(this, other);
            }

            return this.GetType().Equals(other.GetType()) && Id.Equals(other.Id);
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as EntityWithTypedId<TId>);
        }

        public override int GetHashCode()
        {
            if (this.cachedHashCode.HasValue)
            {
                return this.cachedHashCode.Value;
            }

            if (IsTransient())
            {
                this.cachedHashCode = base.GetHashCode();
            }
            else
            {
                int hashCode = this.GetType().GetHashCode();

                hashCode = (hashCode * HashMultiplier) ^ Id.GetHashCode();

                this.cachedHashCode = hashCode;
            }

            return this.cachedHashCode.Value;
        }
    }
}
